{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "13cd1c3e",
   "metadata": {},
   "source": [
    "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langchain-ai/langchain-academy/blob/main/module-1/agent-memory.ipynb) [![Open in LangChain Academy](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66e9eba12c7b7688aa3dbb5e_LCA-badge-green.svg)](https://academy.langchain.com/courses/take/intro-to-langgraph/lessons/58239417-lesson-7-agent-with-memory)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "8c451ffd-a18b-4412-85fa-85186824dd03",
   "metadata": {},
   "source": [
    "# Agent memory\n",
    "\n",
    "## Review\n",
    "\n",
    "Previously, we built an agent that can:\n",
    "\n",
    "* `act` - let the model call specific tools \n",
    "* `observe` - pass the tool output back to the model \n",
    "* `reason` - let the model reason about the tool output to decide what to do next (e.g., call another tool or just respond directly)\n",
    "\n",
    "![Screenshot 2024-08-21 at 12.45.32 PM.png](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66dbab7453080e6802cd1703_agent-memory1.png)\n",
    "\n",
    "## Goals\n",
    "\n",
    "Now, we're going extend our agent by introducing memory."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d2b4b45b-cbaa-41b1-b3ed-f6b0645be3f9",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%capture --no-stderr\n",
    "%pip install --quiet -U langchain_openai langchain_core langgraph"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "2b0cfa99",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os, getpass\n",
    "\n",
    "def _set_env(var: str):\n",
    "    if not os.environ.get(var):\n",
    "        os.environ[var] = getpass.getpass(f\"{var}: \")\n",
    "\n",
    "_set_env(\"OPENAI_API_KEY\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02eff247-a2aa-4f7a-8be1-73dfebfecc63",
   "metadata": {},
   "source": [
    "We'll use [LangSmith](https://docs.smith.langchain.com/) for [tracing](https://docs.smith.langchain.com/concepts/tracing)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "74ef2ff0",
   "metadata": {},
   "outputs": [],
   "source": [
    "_set_env(\"LANGCHAIN_API_KEY\")\n",
    "os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n",
    "os.environ[\"LANGCHAIN_PROJECT\"] = \"langchain-academy\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9c5f123b-db5d-4816-a6a3-2e4247611512",
   "metadata": {},
   "source": [
    "This follows what we did previously."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "46647bbe-def5-4ea7-a315-1de8d97c8288",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "def multiply(a: int, b: int) -> int:\n",
    "    \"\"\"Multiply a and b.\n",
    "\n",
    "    Args:\n",
    "        a: first int\n",
    "        b: second int\n",
    "    \"\"\"\n",
    "    return a * b\n",
    "\n",
    "# This will be a tool\n",
    "def add(a: int, b: int) -> int:\n",
    "    \"\"\"Adds a and b.\n",
    "\n",
    "    Args:\n",
    "        a: first int\n",
    "        b: second int\n",
    "    \"\"\"\n",
    "    return a + b\n",
    "\n",
    "def divide(a: int, b: int) -> float:\n",
    "    \"\"\"Divide a and b.\n",
    "\n",
    "    Args:\n",
    "        a: first int\n",
    "        b: second int\n",
    "    \"\"\"\n",
    "    return a / b\n",
    "\n",
    "tools = [add, multiply, divide]\n",
    "llm = ChatOpenAI(model=\"gpt-4o\")\n",
    "llm_with_tools = llm.bind_tools(tools)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "a9092b40-20c4-4872-b0ed-be1b53a15ef3",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langgraph.graph import MessagesState\n",
    "from langchain_core.messages import AIMessage, HumanMessage, SystemMessage\n",
    "\n",
    "# System message\n",
    "sys_msg = SystemMessage(content=\"You are a helpful assistant tasked with performing arithmetic on a set of inputs.\")\n",
    "\n",
    "# Node\n",
    "def assistant(state: MessagesState):\n",
    "   return {\"messages\": [llm_with_tools.invoke([sys_msg] + state[\"messages\"])]}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "771123a3-91ac-4076-92c0-93bcd69cf048",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/jpeg": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from langgraph.graph import START, StateGraph\n",
    "from langgraph.prebuilt import tools_condition, ToolNode\n",
    "from IPython.display import Image, display\n",
    "\n",
    "# Graph\n",
    "builder = StateGraph(MessagesState)\n",
    "\n",
    "# Define nodes: these do the work\n",
    "builder.add_node(\"assistant\", assistant)\n",
    "builder.add_node(\"tools\", ToolNode(tools))\n",
    "\n",
    "# Define edges: these determine how the control flow moves\n",
    "builder.add_edge(START, \"assistant\")\n",
    "builder.add_conditional_edges(\n",
    "    \"assistant\",\n",
    "    # If the latest message (result) from assistant is a tool call -> tools_condition routes to tools\n",
    "    # If the latest message (result) from assistant is a not a tool call -> tools_condition routes to END\n",
    "    tools_condition,\n",
    ")\n",
    "builder.add_edge(\"tools\", \"assistant\")\n",
    "react_graph = builder.compile()\n",
    "\n",
    "# Show\n",
    "display(Image(react_graph.get_graph(xray=True).draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e830b7ae-3673-4cc6-8627-4740b7b8b217",
   "metadata": {},
   "source": [
    "## Memory\n",
    "\n",
    "Let's run our agent, as before."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "596a71a0-1337-44d4-971d-f80c367bd868",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "Add 3 and 4.\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  add (call_zZ4JPASfUinchT8wOqg9hCZO)\n",
      " Call ID: call_zZ4JPASfUinchT8wOqg9hCZO\n",
      "  Args:\n",
      "    a: 3\n",
      "    b: 4\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: add\n",
      "\n",
      "7\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "The sum of 3 and 4 is 7.\n"
     ]
    }
   ],
   "source": [
    "messages = [HumanMessage(content=\"Add 3 and 4.\")]\n",
    "messages = react_graph.invoke({\"messages\": messages})\n",
    "for m in messages['messages']:\n",
    "    m.pretty_print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "92f8128c-f4a5-4dee-b20b-3245bd33f6b3",
   "metadata": {},
   "source": [
    "Now, let's multiply by 2!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "b41cc1d7-e6de-4d86-8958-8cf7446f4c22",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "Multiply that by 2.\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  multiply (call_prnkuG7OYQtbrtVQmH2d3Nl7)\n",
      " Call ID: call_prnkuG7OYQtbrtVQmH2d3Nl7\n",
      "  Args:\n",
      "    a: 2\n",
      "    b: 2\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: multiply\n",
      "\n",
      "4\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "The result of multiplying 2 by 2 is 4.\n"
     ]
    }
   ],
   "source": [
    "messages = [HumanMessage(content=\"Multiply that by 2.\")]\n",
    "messages = react_graph.invoke({\"messages\": messages})\n",
    "for m in messages['messages']:\n",
    "    m.pretty_print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "26e65f3c-e1dc-4a62-b8ab-02b33a6ff268",
   "metadata": {},
   "source": [
    "We don't retain memory of 7 from our initial chat!\n",
    "\n",
    "This is because [state is transient](https://github.com/langchain-ai/langgraph/discussions/352#discussioncomment-9291220) to a single graph execution.\n",
    "\n",
    "Of course, this limits our ability to have multi-turn conversations with interruptions. \n",
    "\n",
    "We can use [persistence](https://langchain-ai.github.io/langgraph/how-tos/persistence/) to address this! \n",
    "\n",
    "LangGraph can use a checkpointer to automatically save the graph state after each step.\n",
    "\n",
    "This built-in persistence layer gives us memory, allowing LangGraph to pick up from the last state update. \n",
    "\n",
    "One of the easiest checkpointers to use is the `MemorySaver`, an in-memory key-value store for Graph state.\n",
    "\n",
    "All we need to do is simply compile the graph with a checkpointer, and our graph has memory!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "637fcd79-3896-42e4-9131-e03b123a0a90",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langgraph.checkpoint.memory import MemorySaver\n",
    "memory = MemorySaver()\n",
    "react_graph_memory = builder.compile(checkpointer=memory)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "ff8fc3bf-3999-47cb-af34-06b2b94d7192",
   "metadata": {},
   "source": [
    "When we use memory, we need to specify a `thread_id`.\n",
    "\n",
    "This `thread_id` will store our collection of graph states.\n",
    "\n",
    "Here is a cartoon:\n",
    "\n",
    "* The checkpointer write the state at every step of the graph\n",
    "* These checkpoints are saved in a thread \n",
    "* We can access that thread in the future using the `thread_id`\n",
    "\n",
    "![state.jpg](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66e0e9f526b41a4ed9e2d28b_agent-memory2.png)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "f722a1d6-e73c-4023-86ed-8b07d392278d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "Add 3 and 4.\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  add (call_MSupVAgej4PShIZs7NXOE6En)\n",
      " Call ID: call_MSupVAgej4PShIZs7NXOE6En\n",
      "  Args:\n",
      "    a: 3\n",
      "    b: 4\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: add\n",
      "\n",
      "7\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "The sum of 3 and 4 is 7.\n"
     ]
    }
   ],
   "source": [
    "# Specify a thread\n",
    "config = {\"configurable\": {\"thread_id\": \"1\"}}\n",
    "\n",
    "# Specify an input\n",
    "messages = [HumanMessage(content=\"Add 3 and 4.\")]\n",
    "\n",
    "# Run\n",
    "messages = react_graph_memory.invoke({\"messages\": messages},config)\n",
    "for m in messages['messages']:\n",
    "    m.pretty_print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c91a8a16-6bf1-48e2-a889-ae04a37c7a2b",
   "metadata": {},
   "source": [
    "If we pass the same `thread_id`, then we can proceed from from the previously logged state checkpoint! \n",
    "\n",
    "In this case, the above conversation is captured in the thread.\n",
    "\n",
    "The `HumanMessage` we pass (`\"Multiply that by 2.\"`) is appended to the above conversation.\n",
    "\n",
    "So, the model now know that `that` refers to the `The sum of 3 and 4 is 7.`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "ee38c6ef-8bfb-4c66-9214-6f474c9b8451",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "Add 3 and 4.\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  add (call_MSupVAgej4PShIZs7NXOE6En)\n",
      " Call ID: call_MSupVAgej4PShIZs7NXOE6En\n",
      "  Args:\n",
      "    a: 3\n",
      "    b: 4\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: add\n",
      "\n",
      "7\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "The sum of 3 and 4 is 7.\n",
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "Multiply that by 2.\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  multiply (call_fWN7lnSZZm82tAg7RGeuWusO)\n",
      " Call ID: call_fWN7lnSZZm82tAg7RGeuWusO\n",
      "  Args:\n",
      "    a: 7\n",
      "    b: 2\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: multiply\n",
      "\n",
      "14\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "The result of multiplying 7 by 2 is 14.\n"
     ]
    }
   ],
   "source": [
    "messages = [HumanMessage(content=\"Multiply that by 2.\")]\n",
    "messages = react_graph_memory.invoke({\"messages\": messages}, config)\n",
    "for m in messages['messages']:\n",
    "    m.pretty_print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c4b7774e-566f-4c92-9429-ed953bcacaa5",
   "metadata": {},
   "source": [
    "## LangGraph Studio\n",
    "\n",
    "--\n",
    "\n",
    "**⚠️ DISCLAIMER**\n",
    "\n",
    "*Running Studio currently requires a Mac. If you are not using a Mac, then skip this step.*\n",
    "\n",
    "--\n",
    "\n",
    "Load the `agent` in the UI, which uses `module-1/studio/agent.py` set in `module-1/studio/langgraph.json`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6d72986c-ff6f-4f81-b585-d268e2710e53",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
